package com.such.kit;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import com.such.kit.validate.ValidateDataType;

/**
 * @作者 SUCH
 * @日期 2017-3-14 下午7:24:12
 * @描述 数学计算工具类
 */
public class MathCalculate {

	/**
	 * <p>方法名：add</p>
	 * <p>描述：为浮点型提供精确加法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相加后的值
	 */
	public static BigDecimal add(BigDecimal value1, BigDecimal value2) {
		return value1.add(value2);
	}

	/**
	 * <p>方法名：add</p>
	 * <p>描述：为浮点型提供精确加法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相加后的值
	 */
	public static BigDecimal add(double value1, double value2) {
		return add(new BigDecimal(value1), new BigDecimal(value2));
	}

	/**
	 * <p>方法名：add</p>
	 * <p>
	 * 描述：为浮点型提供精确加法运算<br>
	 * 自动根据最大的小数位进行四舍五入，当字符串无法被转换为数字则返回 0<br>
	 * </p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相加后的值
	 */
	public static BigDecimal add(String value1, String value2) {
		int scale = countMaxScale(value1, 0);
		scale = countMaxScale(value2, scale);
		return round(new BigDecimal(value1).add(new BigDecimal(value2)), scale);
	}

	/**
	 * <p>方法名：subtract</p>
	 * <p>描述：为浮点型提供精确减法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相减后的值
	 */
	public static BigDecimal subtract(BigDecimal value1, BigDecimal value2) {
		return value1.subtract(value2);
	}

	/**
	 * <p>方法名：subtract</p>
	 * <p>描述：为浮点型提供精确减法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相减后的值
	 */
	public static BigDecimal subtract(double value1, double value2) {
		return subtract(new BigDecimal(value1), new BigDecimal(value2));
	}

	/**
	 * <p>方法名：subtract</p>
	 * <p>
	 * 描述：为浮点型提供精确减法运算<br>
	 * 自动根据最大的小数位进行四舍五入，当字符串无法被转换为数字则返回 0<br>
	 * </p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相减后的值
	 */
	public static BigDecimal subtract(String value1, String value2) {
		int scale = countMaxScale(value1, 0);
		scale = countMaxScale(value2, scale);
		return round(subtract(new BigDecimal(value1), new BigDecimal(value2)), scale);
	}

	/**
	 * <p>方法名：multiply</p>
	 * <p>描述：为浮点型提供精确乘法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相乘后的值
	 */
	public static BigDecimal multiply(BigDecimal value1, BigDecimal value2) {
		return value1.multiply(value2);
	}

	/**
	 * <p>方法名：multiply</p>
	 * <p>描述：为浮点型提供精确乘法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相乘后的值
	 */
	public static BigDecimal multiply(double value1, double value2) {
		return multiply(new BigDecimal(value1), new BigDecimal(value2));
	}

	/**
	 * <p>方法名：multiply</p>
	 * <p>
	 * 描述：为浮点型提供精确加减运算<br>
	 * 自动根据最大的小数位进行四舍五入，当字符串无法被转换为数字则返回 0<br>
	 * </p>
	 * @param value1 值1
	 * @param value2 值2
	 * @return 相乘后的值
	 */
	public static BigDecimal multiply(String value1, String value2) {
		int scale = countMaxScale(value1, 0);
		scale += countMaxScale(value2, scale);
		return round(multiply(new BigDecimal(value1), new BigDecimal(value2)), scale);
	}

	/**
	 * <p>方法名：divide</p>
	 * <p>描述：为浮点型提供精确除法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @param scale 小数部分的精确位数
	 * @param roundingMode RoundingMode枚举值
	 * @return 相除后的值
	 */
	public static BigDecimal divide(BigDecimal value1, BigDecimal value2, int scale, RoundingMode roundingMode) {
		return value1.divide(value2, scale, roundingMode);
	}

	/**
	 * <p>方法名：divide</p>
	 * <p>描述：为浮点型提供精确除法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @param scale 小数部分的精确位数
	 * @param roundingMode RoundingMode枚举值
	 * @return 相除后的值
	 */
	public static BigDecimal divide(double value1, double value2, int scale, RoundingMode roundingMode) {
		return divide(new BigDecimal(value1), new BigDecimal(value2), scale, roundingMode);
	}

	/**
	 * <p>方法名：divide</p>
	 * <p>描述：为浮点型提供精确除法运算</p>
	 * @param value1 值1
	 * @param value2 值2
	 * @param scale 小数部分的精确位数
	 * @param roundingMode RoundingMode枚举值
	 * @return 相除后的值
	 */
	public static BigDecimal divide(String value1, String value2, int scale, RoundingMode roundingMode) {
		return divide(new BigDecimal(value1), new BigDecimal(value2), scale, roundingMode);
	}

	/**
	 * <p>方法名：pow</p>
	 * <p>描述：为浮点型提供精确次方运算</p>
	 * @param value 值
	 * @param n 次方
	 * @return 次方后的值
	 */
	public static BigDecimal pow(BigDecimal value, int n) {
		return value.pow(n);
	}

	/**
	 * <p>方法名：pow</p>
	 * <p>描述：为浮点型提供精确次方运算</p>
	 * @param value 值
	 * @param n 次方
	 * @return 次方后的值
	 */
	public static BigDecimal pow(double value, int n) {
		return pow(new BigDecimal(value), n);
	}

	/**
	 * <p>方法名：pow</p>
	 * <p>描述：为浮点型提供精确次方运算</p>
	 * @param value 值
	 * @param n 次方
	 * @return 次方后的值
	 */
	public static BigDecimal pow(String value, int n) {
		return pow(new BigDecimal(value), n);
	}

	/**
	 * <p>方法名：round</p>
	 * <p>描述：提供精确的小数位四舍五入处理</p>
	 * @param value 值
	 * @param scale 小数部分的精确位数
	 * @return 四舍五入后的值
	 */
	public static BigDecimal round(BigDecimal value, int scale) {
		return value.setScale(scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * <p>方法名：round</p>
	 * <p>描述：提供精确的小数位四舍五入处理</p>
	 * @param value 值
	 * @param scale 小数部分的精确位数
	 * @return 四舍五入后的值
	 */
	public static BigDecimal round(double value, int scale) {
		return round(new BigDecimal(value), scale);
	}

	/**
	 * <p>方法名：round</p>
	 * <p>描述：提供精确的小数位四舍五入处理</p>
	 * @param value 值
	 * @param scale 小数部分的精确位数
	 * @return 四舍五入后的值
	 */
	public static BigDecimal round(String value, int scale) {
		return round(new BigDecimal(value), scale);
	}

	/**
	 * <p>方法名：round</p>
	 * <p>描述：提供精确的小数位四舍五入处理</p>
	 * @param value 值
	 * @param scale 小数部分的精确位数
	 * @param keepDecimal 是否严格保留小数位，即使最后小数位为 0
	 * @return 四舍五入后的值
	 */
	public static String round(String value, int scale, boolean keepDecimal) {
		if (ValidateDataType.validateDouble(value)) {
			BigDecimal returnValue = round(new BigDecimal(value), scale);
			if (keepDecimal) {
				if (scale > 0) {
					StringBuffer pattern = new StringBuffer();
					pattern.append("#0.");
					for (int i = 0; i < scale; i++) {
						pattern.append("0");
					}
					DecimalFormat format = new DecimalFormat(pattern.toString());
					return format.format(returnValue.doubleValue());
				} else {
					return returnValue.toPlainString();
				}
			} else {
				return returnValue.toPlainString();
			}
		}
		return value;
	}

	/**
	 * <p>方法名：abs</p>
	 * <p>描述：取入参绝对值</p>
	 * @param value 值
	 * @return 绝对值
	 */
	public static BigDecimal abs(BigDecimal value) {
		return value.abs();
	}

	/**
	 * <p>方法名：abs</p>
	 * <p>描述：取入参绝对值</p>
	 * @param value 值
	 * @return 绝对值
	 */
	public static BigDecimal abs(double value) {
		return abs(new BigDecimal(value));
	}

	/**
	 * <p>方法名：abs</p>
	 * <p>描述：取入参绝对值</p>
	 * @param value 值
	 * @return 绝对值
	 */
	public static BigDecimal abs(String value) {
		return abs(new BigDecimal(value));
	}

	private static int countMaxScale(String value, int maxScale) {
		int index = value.indexOf(".");
		if (index > -1) {
			String tempStr = value.substring(index + 1);
			int scale = tempStr.length();
			if (scale > maxScale) {
				maxScale = scale;
			}
		}
		return maxScale;
	}

}
